#include<iostream>
#include"func.h"
#include<opencv2/imgcodecs.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/objdetect.hpp>
#include<opencv2/opencv.hpp>
#include<opencv2/ximgproc.hpp>
#include<string>
#include<vector>
#include<fstream>

using namespace std;
using namespace cv;

void fenshuilingfenge()
{
    Mat img,imggray,imgmask,img_;
    Mat maskwatershed;//watershed()函数的参数
    // img_=imread("/home/zhanjiabin/桌面/task/study/changzhou.jpg");//不含标记的原图
    img=imread("/home/zhanjiabin/桌面/task/study/changzhou_.jpg");//含标记1的原图
    cvtColor(img,imggray,COLOR_BGR2GRAY);//转灰度

    Canny(imggray,imgmask,150,300);
    // Mat k=getStructuringElement(0,Size(3,3));
    // morphologyEx(imgmask,imgmask,MORPH_OPEN,k);

    imshow("含标记的原图",img);
    imshow("边缘",imgmask);
    // imshow("不含标记的原图",img_);

    vector<vector<Point>> contours;
    vector<Vec4i> hie;
    findContours(imgmask,contours,hie,RETR_CCOMP,CHAIN_APPROX_SIMPLE);

    //在maskwatershed绘制轮廓用于输入分水岭算法
    maskwatershed=Mat::zeros(imgmask.size(),CV_32S);
    for(int index=0;index<contours.size();index++)
    {
        drawContours(maskwatershed,contours,index,Scalar::all(index+1),-1,8,hie,INT_MAX);
    }

    //分水岭算法处理
    watershed(img,maskwatershed);//分水岭算法函数(输入图，输入输出图)

    vector<Vec3b> colors;//随机生成几种颜色
    for(int i=0;i<contours.size();i++)
    {
        int b=theRNG().uniform(0,255);
        int g=theRNG().uniform(0,255);
        int r=theRNG().uniform(0,255);
        colors.push_back(Vec3b((uchar)b,(uchar)g,(uchar)r));
    }

    Mat resultimg=Mat(img.size(),CV_8UC3);//显示图像
    for(int i=0;i<imgmask.rows;i++)
    {
        for(int j=0;j<imgmask.cols;j++)
        {
            //绘制每个区域的颜色
            int index=maskwatershed.at<int>(i,j);
            if (index==-1)
            {
                resultimg.at<Vec3b>(i,j)=Vec3b(255,255,255);
            }
            else if(index<=0||index>contours.size())
            {
                resultimg.at<Vec3b>(i,j)=Vec3b(0,0,0);
            }
            else
            {
                resultimg.at<Vec3b>(i,j)=colors[index-1];
            }
        }

    }
    // imshow("resultimg",resultimg);
    resultimg=resultimg*0.8+img*0.2;
    imshow("分水岭结果",resultimg);

    //绘制每个区域图像
    for(int n=1;n<=contours.size();n++)
    {
        Mat resimg=Mat(img.size(),CV_8UC3);
        for(int i=0;i<imgmask.rows;i++)
        {
            for(int j=0;j<imgmask.cols;j++)
            {
                int index=maskwatershed.at<int>(i,j);
                if(index==n)
                {
                    resimg.at<Vec3b>(i,j)=img.at<Vec3b>(i,j);
                }
                else
                {
                    resimg.at<Vec3b>(i,j)=Vec3b(0,0,0);
                }
            }
        }
        imshow(to_string(n),resimg);
    }
    waitKey(0);

}

void harrisjiance()
{
    Mat img=imread("/home/zhanjiabin/桌面/task/study/0512_1.jpg",IMREAD_COLOR);

    Mat gray;
    cvtColor(img,gray,COLOR_BGR2GRAY);

    //计算harris系数
    Mat harris;
    int blockSize=2;//邻域半径
    int ape=3;
    cornerHarris(gray,harris,blockSize,ape,0.04);//harris角点检测函数(输入图，评价系数矩阵，邻域大小，，算子半径，权重系数)；

    //归一化
    Mat harrisn;
    normalize(harris,harrisn,0,255,NORM_MINMAX);
    //将图像数据类型转为CV_8U
    convertScaleAbs(harrisn,harrisn);

    //寻找角点
    vector<KeyPoint> keypoints;
    for(int row=0;row<harrisn.rows;row++)
    {
        for(int col=0;col<harrisn.cols;col++)
        {
            int r=harrisn.at<uchar>(row,col);
            if(r>125)
            {
                KeyPoint keypoint;
                keypoint.pt.y=row;
                keypoint.pt.x=col;
                keypoints.push_back(keypoint);
            }
        }
    }

    drawKeypoints(img,keypoints,img);
    imshow("系数矩阵",harrisn);
    imshow("harris角点",img);
    waitKey(0);

}

void stjiaodian()
{
    Mat img=imread("/home/zhanjiabin/桌面/task/study/0512_1.jpg");

    Mat gray;
    cvtColor(img,gray,COLOR_BGR2GRAY);

    //提取角点
    int maxCorners=100;
    double qua=0.01;
    double mindis=0.04;
    vector<Point2f> corners;
    goodFeaturesToTrack(gray,corners,maxCorners,qua,mindis,Mat(),3,false);//托马斯角点检测(输入图，输出角点坐标，角点数，质量等级，角点间最小欧氏距离，掩码矩阵，梯度协方差矩阵尺寸，是否计算harris角点标志)

    //绘制角点
    vector<KeyPoint> keyPoints;

    for(int i=0;i<corners.size();i++)
    {
        KeyPoint keyPoint;
        keyPoint.pt=corners[i];
        keyPoints.push_back(keyPoint);
    }

    drawKeypoints(img,keyPoints,img);
    imshow("img",img);

    waitKey(0);

}

void yaxiangsujiaodianweizhiyouhua()
{
    Mat img=imread("/home/zhanjiabin/桌面/task/study/0512_1.jpg");

    Mat gray;
    cvtColor(img,gray,COLOR_BGR2GRAY);

    int maxC=100;
    double ql=0.01;
    double minD=0.04;
    vector<Point2f> corners;
    goodFeaturesToTrack(gray,corners,maxC,ql,minD,Mat(),3,false);

    //计算亚像素级别角点坐标
    vector<Point2f> corSub=corners;//角点备份防止被函数修改
    Size winSize=Size(5,5);
    Size zeroZone=Size(-1,-1);
    TermCriteria criteria=TermCriteria(TermCriteria::EPS+TermCriteria::COUNT,40,0.001);
    cornerSubPix(gray,corSub,winSize,zeroZone,criteria);//角点位置优化函数(输入图，输入输出角点坐标，搜索窗口大小的一半，死区大小的一半，终止角点优化迭代的条件)

    //输出优化后坐标
    for(size_t i=0;i<corners.size();i++)
    {
        string str=to_string(i);
        str="第"+str+"个角点初始坐标:";
        cout<<str<<corners[i]<<"精细后坐标:"<<corSub[i]<<endl;
    }


}

void orbreg()
{
    Mat img=imread("/home/zhanjiabin/桌面/task/study/test.jpg");

    //创建ORB特征点类变量
    Ptr<ORB> orb=ORB::create(500,//特征点数目
                            1.2f,//金字塔层级间缩放比例
                            8,   //金字塔层数
                            31,  //边缘阈值
                            0,   //原图所在金字塔层数
                            2,   //生成描述子时用的像素点数目
                ORB::HARRIS_SCORE,//特征点评价方法
                            31,  //生成描述子时关键点周围邻域尺寸
                            20   //计算FAST角点时像素值差值的阈值
                            );

    //计算ORB关键点
    vector<KeyPoint> Keypoints;
    orb->detect(img,Keypoints);//计算特征点中关键点函数(输入图，检测结果)

    //计算ORB描述子
    Mat des;
    orb->compute(img,Keypoints,des);//计算描述子函数(输入图，关键点，描述子)

    //绘制特征点
    Mat imgA;
    img.copyTo(imgA);
    //绘制不含角度的大小和结果
    drawKeypoints(img,Keypoints,img,Scalar(255,255,255));
    //绘制含有角度和大小的结果
    drawKeypoints(img,Keypoints,imgA,Scalar(255,255,255),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

    //显示结果
    imshow("不含角度和大小的结果",img);
    imshow("含有角度和大小的结果",imgA);
    waitKey(0);

}

void orb_features(Mat &gray,vector<KeyPoint> &keypionts,Mat &descriptions)
{
    Ptr<ORB> orb=ORB::create(1000,1.2f);
    orb->detect(gray,keypionts);
    orb->compute(gray,keypionts,descriptions);
}

void tezhengdianpipei()
{
    Mat img1=imread("/home/zhanjiabin/桌面/task/study/test.jpg");//原图
    VideoCapture cap(0);
    Mat img2;//相机获取图

    //提取orb特征点
    vector<KeyPoint> keypoints1,keypoints2;
    Mat descriptions1,descriptions2;

    //计算原图特征点
    orb_features(img1,keypoints1,descriptions1);
    
    //特征点匹配变量定义
    vector<DMatch> matches;//定义存放匹配结果的变量
    BFMatcher matcher(NORM_HAMMING);//定义特征点匹配类使用汉明变量

    //定义汉明距离阈值
    double minD=10000,maxD=0;

    double dist;//匹配点汉明距离

    vector<DMatch> good_matches;//存放较好匹配点

    while (1)
    {
        cap.read(img2);

        //计算相机获取图特征点
        orb_features(img2,keypoints2,descriptions2);

        //特征点匹配
        matcher.match(descriptions1,descriptions2,matches);//特征点匹配函数(原图特征点描述子，待匹配图特征点描述子，匹配结果)
        cout<<"匹配成功特征点数目"<<matches.size()<<endl;

        //通过汉明距离筛选匹配结果
        for(int i=0;i<matches.size();i++)
        {
            dist=matches[i].distance;
            if(dist<minD) minD=dist;
            if(dist>maxD) maxD=dist;
        }

        //输出匹配结果中最大汉明距离和最小汉明距离
        cout<<"minD="<<minD<<endl;
        cout<<"maxD="<<maxD<<endl;

        //将较大汉明距离的匹配点移除
        for(int i=0;i<matches.size();i++)
        {
            if(matches[i].distance<=max(2*minD,20.0));
            {
                good_matches.push_back(matches[i]);
            }
        }
        cout<<"剩余特征点数"<<good_matches.size()<<endl;

        //绘制匹配结果
        Mat outimg,outimg1;
        // drawMatches(img1,keypoints1,img2,keypoints2,matches,outimg);//绘制匹配结果函数(原图，原图关键点，待匹配图，待匹配图关键点，描述子匹配结果，输出图)
        drawMatches(img1,keypoints1,img2,keypoints2,good_matches,outimg1);
        // imshow("未筛选结果",outimg);
        imshow("筛选后结果",outimg1);

        waitKey(1);

    }
    

}

void match_min(vector<DMatch> matches,vector<DMatch> &good_matches)
{
    double minD=1000,maxD=0;
    for(int i=0;i<matches.size();i++)
    {
        double dist=matches[i].distance;
        if(dist<minD) minD=dist;
        if(dist>maxD) maxD=dist;
    }
    cout<<"minD="<<minD<<endl;
    cout<<"maxD="<<maxD<<endl;

    for(int i=0;i<matches.size();i++)
    {
        if(matches[i].distance<=max(2*minD,20.0))
        {
            good_matches.push_back(matches[i]);
        }
    }
}

void ransac(vector<DMatch> matches,vector<KeyPoint> queryKetPoint,vector<KeyPoint> trainKeyPoint,vector<DMatch> &matches_ransac)//ransac算法实现
{
    //定义保存匹配点对的坐标
    vector<Point2f> srcPoints(matches.size()),dstPoints(matches.size());
    //保存从关键点中提取到的匹配点坐标
    for(int i=0;i<matches.size();i++)
    {
        srcPoints[i]=queryKetPoint[matches[i].queryIdx].pt;
        dstPoints[i]=trainKeyPoint[matches[i].trainIdx].pt;
    }

    //匹配点对进行ransac过滤
    vector<int> inlierMask(srcPoints.size());
    findHomography(srcPoints,dstPoints,RANSAC,5,inlierMask);//单应矩阵计算函数(原图特征点。目标图特征点，计算方法标志，重投影最大误差，迭代次数)
    for(int i=0;i<inlierMask.size();i++)
    {
        if(inlierMask[i])
        {
            matches_ransac.push_back(matches[i]);
        }
    }

}

void ransacyouhua()
{
    Mat img1=imread("/home/zhanjiabin/桌面/task/study/testp.jpg");
    Mat img2=imread("/home/zhanjiabin/桌面/task/study/test.jpg");

    //提取orb特征点
    vector<KeyPoint> Keypoints1,Keypoints2;
    Mat descriptions1,descriptions2;
    
    //基于区域分割的orb特征点提取
    orb_features(img1,Keypoints1,descriptions1);
    orb_features(img2,Keypoints2,descriptions2);

    //特征点匹配
    vector<DMatch> matches,good_min,good_ransac;
    BFMatcher matcher(NORM_HAMMING);
    matcher.match(descriptions1,descriptions2,matches);
    cout<<"matches="<<matches.size()<<endl;

    //最小汉明距离
    match_min(matches,good_min);
    cout<<"good_min"<<good_min.size()<<endl;

    //利用rancac算法筛选匹配结果
    ransac(good_min,Keypoints1,Keypoints2,good_ransac);
    cout<<"good_matches.size="<<good_ransac.size()<<endl;

    //绘制匹配结果
    Mat outimg,outimg1,outimg2;
    drawMatches(img1,Keypoints1,img2,Keypoints2,matches,outimg);
    drawMatches(img1,Keypoints1,img2,Keypoints2,good_min,outimg1);
    drawMatches(img1,Keypoints1,img2,Keypoints2,good_ransac,outimg2);
    imshow("未筛选结果",outimg);
    imshow("最小汉明距离筛选",outimg1);
    imshow("ransac算法筛选",outimg2);
    waitKey(0);

}
